#ifndef MESHFUNCTIONS_HPP
#define MESHFUNCTIONS_HPP

#include "meshTypes_fwd.hpp"
#include "mesh.hpp"
#include "structMeshFunctions.hpp"
#include <iostream>
#include <utility>

namespace hms
{

/* creates a structured, rectangular m x n mesh aligned with x and y axis */
Mesh createRectangularMesh(
	Index  nCellsX,
	Index  nCellsY,
	scalar dX,
	scalar dY,
	scalar offsetX = 0,
	scalar offsetY = 0
);


auto findAdjacentCells(
	const Ref<const ArrayX<char>>& nDomainCellEdges,
	const Ref<const Array4Xi>& domainCellEdges,
	Index nEdges
)-> Array2Xi;


bool hasEmptyParent(const Ref<const Array2Xi>& cells, Index edge);


auto findEdgesWEmptyParent( const Ref<const Array2Xi>& cells )
-> IdxVector;


void setGhostsAsAdjacent(
	Array2Xi& adjacentCells, Index nDomainCells, Index nBoundaryEdges
);


void swapEdges(
	Index edgeA,
	Index edgeB,
	Array2Xi& edgeVertexIndices,
	Array2Xi& edgeAdjacentCells
);

void swapEdges(
	Index edgeA,
	Index edgeB,
	Array2Xi& edgeVertexIndices,
	Array2Xi& edgeAdjacentCells,
	Array4Xi& domainCellEdges
);

auto edgesToSwap(
	const IdxVector& boundaryEdges,
	const Ref<const Array2Xi>& parentCells,
	Index nEdges,
	Index nInnerEdges
) -> Array2Xi;


Mesh edgesAndCellsToMesh(
	Matrix2Xs&& vertexCoords,
	Array2Xi&& edgeVertexIndices,
	ArrayX<char>&& nDomainCellEdges,
	Array4Xi&&      domainCellEdges,
	const Array4Xi& domainCellVertices = {}
);

Mesh cellVerticesToMesh(
	Matrix2Xs&& vertexCoords,
	ArrayX<char>&& nDomainCellEdges,
	const Array4Xi& domainCellVertices
);


auto findDomainCellEdges(
	Index nVertices,
	const Array2Xi& edgeVertices
) -> std::pair<ArrayX<char>, Array4Xi>;

auto findDomainCellEdges(const Mesh&)
-> std::pair<ArrayX<char>, Array4Xi>;

Mesh edgesToMesh(
	Matrix2Xs&& vertexCoords,
	Array2Xi&& edgeVertices
);

} // end namespace hms

#endif